基于Transformer fine-tune领域特定分词器

归纳使用HanLP训练基于Transformer的tokenizer的过程,写着写着发现开始介绍虚拟环境了😅

Falldio武汉

Before you read

本文的主要内容

  • 基于 Hanlp 2.x Python API 搭建某一领域特定的分词器。

    • 搭建 Python 虚拟开发环境。

    • 准备少量标注数据集。

    • 利用 HanLP 的 transformer tokenizer 对 bert-base-chinese 进行 fine-tune。

    • 模型的保存和使用方式。

本文将不包括

Note: 本文将只把深度学习部分当作一个黑箱模型使用,如果你仍然想要对自然语言处理有更多的了解,下面是一些科普性质的资料。如果需要更深层次的理解,可能需要通过网课、教科书和论文等手段了。

开发环境搭建

这一节内容讲解 Python 开发环境搭建和虚拟环境设置,是一个很傻瓜🤓的教程。这一节的安装配置利用到了 Annaconda,如果本机已经有了 Python 环境的话,直接跳过即可。

安装 Annaconda

长话短说,Anaconda 是一个 Python 和 R 语言的发行版本,我们这里主要使用其中的 Conda 来进行 Python 的版本管理、环境管理和包管理。其优势在于你不需要自行管理 Python 的虚拟环境和 Python 版本,省去了不少麻烦(想象一下你需要自行管理本机的 Python 2.x 和 Python 3.x 环境,在运行对 Python 版本要求不同的软件时,你可能需要手动设置 Python 有关的环境变量,这也太麻烦了😡

Annaconda 的安装包可以直接在官网获取,如果因为国内网络环境安装太慢,可以在清华大学的镜像仓库下载。

如果你的系统恰巧是 MacOS 或 Linux,而且下载的是 shell 脚本(.sh 文件),你可能需要用类似于 chmod 的命令改变文件权限。

关于具体的文件安装,如果是可执行文件,直接运行即可,如果是 shell 脚本,命令行直接运行更加方便。

安装过程中的一些必要设置

对于 Windows,你需要注意在安装时设置将 Anaconda 的路径加入环境变量 $PATH 中,这样才能确保后面直接在 shell 使用 Conda 命令。

安装后的一些必要设置

为了保证日后下载包的速度,不妨将清华大学的镜像仓库加入 conda 设置中:

sh
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/

安装后的确认

当你安装完成后,打开 shell,应该已经能发现一些不同:你的当前命令前出现了 (base) 字样,这意味着现在我们处于一个名为 base 的虚拟环境虚拟环境的概念我们下一小节会简单介绍

如前所述,Anaconda 是一个 Python 和 R 语言的发行版本,在安装过程中它会:

  1. 自动安装一个 Python 作为其默认的 Python 版本。
  2. 自动安装 Conda 作为包管理工具(包管理工具这一概念我相信你已经很熟悉了,因此不赘言它的概念和好处。如果你还不熟悉的话,可以查看一些包管理器的官网,它们的介绍页面应该有更严谨翔实的说法,比如 Python 的 pip、NodeJS 的 npmyarn,MacOS 的 homebrew,Windows 的 wingetchocolatey scoop)。
  3. 自动创建一个名为 base 的 Python 虚拟环境,作为其默认的 Python 虚拟环境。

HanLP 的配置

搭建虚拟环境

Again,虚拟环境只是一个建议,它不是必选项。如果你在未来会比较频繁的进行 Python 开发,你迟早需要接触这个概念。节约时间的话完全可以跳过。

既然我们已经有了 conda 和 Python,想必安装 HanLP 之类的依赖对你来说已经不是难题了。但是为了依赖安全考虑,我们需要搭建一个新的虚拟环境,我们将在这个虚拟环境里运行我们的分词器项目。在本文档的例子里,我将这个环境命名为 tok

sh
conda create -n tok

![](/Users/liucheng/Desktop/ 截屏 2023-03-16 19.17.55.png)

如果我们按照提示切换到 tok 环境:

sh
conda activate tok

则命令前方的 base 将变为 tok

为什么需要虚拟环境?

现在我们已经有了两个虚拟环境了, basetok ,我们总算可以更实际地介绍什么是虚拟环境,以及为什么要使用虚拟环境了🎉。这小节内容完全是和教程无关的,你也可以直接跳过~

虚拟环境有点像是虚拟机的概念,它隔离的是 Python 的包和 Python 本身,也就是说,每个虚拟环境会独立存放一个 Python 包的版本,也会单独指定一个 Python 版本(sure,Python 是不会重复安装的,虚拟环境里会单独设置 python 的环境变量)。

我们下面用两个例子来说明为什么虚拟环境是必要的:

  1. 我们在 base 下面需要用 Python2,而 tok 下需要 Python3,你应该知道这两个大版本的 Python 是语法不兼容的,但却会使用同一个环境变量。如果没有虚拟环境,每次我们可能都要额外指定:运行 a 脚本要用 Python2,运行 b 程序需要用 Python3。如果是用虚拟环境加以区分,则省去了指定 Python 版本的麻烦,只要在虚拟环境之间切换就可以了。
  2. 我们在两个虚拟环境下需要使用版本不同的同一个包,如果不使用虚拟环境,包的冲突是无法避免的。而有了虚拟环境,在两个环境里面我们可以使用不同的版本,两个项目会相安无事。此外,如果我们在虚拟环境里配置项目,一旦我们想要使用类似于 pip freeze > requirements.txt 的方式导出该项目的包依赖(在写开源软件的时候这通常是必要的),我们就能确保导出的只是这个项目的包依赖,不会带上别的东西。

安装 Python、HanLP 等

万事俱备,我们可以简单使用 conda 安装一个 Python(如下面示例,这个 Python 版本可以任意指定),然后用这个 Python 的 pip 工具安装 HanLP。HanLP 相关的依赖有很多,而这些会被 pip 自动安装到当前的 tok 虚拟环境中,全然不用担心这些依赖日后和其他项目发生冲突,也不必担心日后安装了更高版本的相关依赖导致 HanLP 无法运行,只要做好虚拟环境隔离就可以~

sh
conda install python=3.10
pip install hanlp

训练领域特定分词器

我们在这一节开始真正利用 HanLP 训练分词器。在文档开始已经提到,下面并不会介绍深层次的原理,我们这里只简单的把 transformer 当作黑箱,投进去一些标注好的数据,使其能够发现规律,完成更多的分词任务即可。

需要注意的是,我们要利用的 transformer API 实际上包含一个已经进行过预训练的 bert-base-chinese 模型,这个模型已经利用通用的中文语料库训练过。问题在于,通用的语料库可能不能很好的涵盖特定领域的语料,或者特定领域语料的数量太少,在预训练时可能已经被当作噪声处理了。因此,我们实际上是在经过通用语料库预训练模型的基础上进行 fine-tune

这里的 fine-tune 是深度学习领域的一个术语,翻译过来大概是 “微调” 的意思,它指的是我们已经有了一个经过大量数据训练的模型(比如我们的 bert-base-chinese),我们的需求(特定领域的分词)和这个大模型原本要解决的问题有了些许差异,此时我们可以保留该模型的初始权重,利用领域特定的数据集接着训练模型,使其能更好的满足我们特定领域的需求(从广而不精到领域专家)。

你可能会好奇这里的 bert-base-chinese 和 transformer 模型的关系是什么。实际上 bert 是 transformer 的一个变体,它们在 transformer 的部分实际上没什么大的区别。bert 的全称是 Bidirectional Encoder Representation from Transformers,如果你想看原论文,详细了解两者区别的话,可以点击👉这里。顺带一提,时下大火的 GPT 模型(Generative Pre-trained Transformer)也源自 transformer。如今 Google 被 Microsoft 联合 OpenAI ChatGPT 推出的 New Bing 降维打击,这一切的根源居然是 Google 自己提出的 Transformer,实在是很有戏剧性。

数据集的准备

我们的训练数据集遵照 HanLP,大概是这样的模式:

莫干山高新区	通航产业园	鼎盛路	28	号	3	号楼
永平路	与	长虹东街	交叉路口	往	北	约	150	米
浙江省	湖州市	德清县	舞阳街道	山民村	9	-	1	号	白果树
武康镇	贵和街	194	号
浙江省	湖州市	德清县	钟管镇	南湖社区	南湖路	272	号

如果你要解决的不是分词问题,你需要查看 HanLP 的其他用例。

模型训练与保存

模型训练与保存的代码大概如下所示,如果需要了解每个参数意义的话,你需要参考文档最开始所说的资料研究,但是如果只是用来训练一个简单的分词器,你完全可以使用默认参数,只需要给出训练集、测试集、模型保存路径即可。

python
tokenizer = TransformerTaggingTokenizer()
save_dir = 'your model save path'

tokenizer.fit(
    your dataset,
    your dataset,  # Conventionally, no devset is used. See Tian et al. (2020).
    save_dir,
    'bert-base-chinese',
    max_seq_len=300,
    char_level=True,
    hard_constraint=True,
    sampler_builder=SortingSamplerBuilder(batch_size=32),
    epochs=3,
    adam_epsilon=1e-6,
    warmup_steps=0.1,
    weight_decay=0.01,
    word_dropout=0.1,
    seed=1660853059,
)
tokenizer.evaluate(your test set, save_dir)

模型训练完成之后会自动保存在 save_dir 下,保存结果会是多个文件,包含模型结构、权重信息等。

加载和使用已保存的模型

HanLP API 的调用没什么好说的,这里的 print 函数会以 list 的形式输出分词结果。

python
model = hanlp.load(save_dir)
print(model("湖北省武汉市珞瑜路129号"))

What to do next?

如果顺利的话,你现在应该已经得到了一个领域特定的分词器,我想你可能有两件想做的事情🤔,但是这已经不是本文档的覆盖范围了,因此我简单给出一些建议:

  • 训练其他模型以应对更多别的需求:
    • 你可以参考 HanLP 的文档,进一步了解 HanLP 的应用。
    • 或者你已经不满足于既定的模型结构,想要自行设计模型,你可以参考下面的资料:
      • PyTorchTensorflowpaddlepaddle 等深度学习框架。
      • keras 等更高级的深度学习库,它们通常会自行封装一些 layer 供你使用,让你可以直接像搭积木一样构建模型。
  • 了解模型如何部署到实际项目里:
    • 你可能需要参考 PyTorch 的模型部署文档,因为 HanLP 对 Transformer 的封装实际上是基于 PyTorch 实现的。
    • 你可能需要参考 Python 或者其他后端编程语言搭建网络服务器的方式将模型封装成服务。